package com.xiaoyu.lanling.feature.voicecall.controller

import `in`.srain.cube.concurrent.SimpleTask
import `in`.srain.cube.util.*
import `in`.srain.cube.util.internal.AppCallback
import `in`.srain.cube.util.internal.AppConsumer
import `in`.srain.cube.views.CheckImageButton
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Service
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.media.AudioManager
import android.media.AudioManager.OnAudioFocusChangeListener
import android.media.MediaPlayer
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.SystemClock
import android.os.Vibrator
import android.provider.Settings
import android.text.TextUtils
import android.view.View
import android.widget.Chronometer
import android.widget.ImageButton
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.FragmentActivity
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.postprocessors.IterativeBoxBlurPostProcessor
import com.tbruyelle.rxpermissions2.RxPermissions
import com.xiaoyu.base.app.App
import com.xiaoyu.base.app.AppContext
import com.xiaoyu.base.app.GlobalUI
import com.xiaoyu.base.data.UserInfoDataProvider
import com.xiaoyu.base.model.User
import com.xiaoyu.base.utils.RxUtils
import com.xiaoyu.base.utils.extensions.setOnClickDebounceListener
import com.xiaoyu.base.utils.extensions.setViewTag
import com.xiaoyu.base.utils.time.CountDown
import com.xiaoyu.lanling.R
import com.xiaoyu.lanling.common.Constant
import com.xiaoyu.lanling.common.Constant.RequestCode.SETTINGS_OVERLAY_PERMISSION
import com.xiaoyu.lanling.data.NotificationData
import com.xiaoyu.lanling.feature.voicecall.CallFloatWindowManager
import com.xiaoyu.lanling.feature.voicecall.activity.ChatCallActivity
import com.xiaoyu.lanling.feature.voicecall.data.CallData
import com.xiaoyu.lanling.feature.voicecall.data.CallData.ActionType.ACCEPT
import com.xiaoyu.lanling.feature.voicecall.data.CallData.ActionType.CANCEL
import com.xiaoyu.lanling.feature.voicecall.data.CallData.ActionType.HANGUP
import com.xiaoyu.lanling.feature.voicecall.data.CallData.ActionType.REJECT
import com.xiaoyu.lanling.feature.voicecall.model.ActionMessageType
import com.xiaoyu.lanling.feature.voicecall.model.HangupReason
import com.xiaoyu.lanling.feature.voicecall.model.MessageType.ACTION
import com.xiaoyu.lanling.feature.voicecall.model.MessageType.SYSTEM
import com.xiaoyu.lanling.feature.voicecall.model.SystemMessageType
import com.xiaoyu.lanling.feature.voicecall.util.VoiceCallNotificationUtils
import com.xiaoyu.lanling.feature.main.activity.MainActivity
import com.xiaoyu.lanling.feature.voicecall.log.VoiceCallLogger
import com.xiaoyu.lanling.media.image.ImageViewUtil
import com.xiaoyu.lanling.media.image.UserImageLoadParam
import com.xiaoyu.lanling.router.Router
import com.xiaoyu.lanling.util.TextViewUtil
import com.xiaoyu.lanling.view.UserAvatarDraweeView
import com.xiaoyu.lanling.view.text.UserNameTextView
import com.xiaoyu.lib_av.datamodel.*
import com.xiaoyu.lib_av.datamodel.CallHangUpType.HangUpTypeDef
import com.xiaoyu.lib_av.datamodel.CallParams.Companion.fromJson
import com.xiaoyu.lib_av.datamodel.CallResponseType.REFUSE
import com.xiaoyu.lib_av.listener.AbstractVoiceCallLifecycleListener
import com.xiaoyu.lib_av.manager.CallManager
import com.xiaoyu.net.util.NetUtils
import com.yhao.floatwindow.PermissionUtil
import io.reactivex.Completable
import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.subjects.PublishSubject
import kotlinx.android.synthetic.main.activity_chat_call.*
import java.util.concurrent.TimeUnit

class ChatCallViewController(private val mFragmentActivity: FragmentActivity) : AbstractVoiceCallLifecycleListener() {

    private var mMainTaskTopActivity: Activity? = null
    private var mUserAvatar: UserAvatarDraweeView? = null
    private var mUserNickname: UserNameTextView? = null
    private var mVoiceStatus: TextView? = null
    private var mVoiceTime: Chronometer? = null
    private var mVoiceNetworkStatus: TextView? = null
    private var mCallLayout: RelativeLayout? = null
    private var mVoiceMute: CheckImageButton? = null
    private var mVoiceCancel: ImageButton? = null
    private var mVoiceHandsFree: CheckImageButton? = null
    private var mVoiceHandsFreeTitle: TextView? = null
    private var mVoiceReceiveLayout: RelativeLayout? = null
    private var mVoiceReject: ImageButton? = null
    private var mVoiceAnswer: ImageButton? = null
    private var mVoiceFullScreenExit: ImageButton? = null

    private var mRingtoneMediaPlayer: MediaPlayer? = null
    private var mVibrator: Vibrator? = null

    private val mIsCaller: Boolean
    private val mFuid: String?
    private val mFromType: String?
    private var mCallDurationInS: Long = 0
    private var mWifiOffPublishSubject: PublishSubject<Boolean>? = null
    private var mVibratorDisposable: Disposable? = null
    private val mNotificationDisposable: Disposable? = null
    private var mDisplayUserDisposable: Disposable? = null
    private var mWifiDisposable: Disposable? = null
    private var mCountDownDisposable: Disposable? = null
    private var mIsHeadset = false
    private var mDisableAudioStartTime = 0L

    fun onResume() {
        mMainTaskTopActivity = App.getInstance().topActivity
        dismissCallNotification()
        CallFloatWindowManager.instance.hideAndStopFloatWindow(mFragmentActivity)
    }

    fun onStop() {
        if (isCalling) {
            if (!TextUtils.isEmpty(mFuid)) {
                showCallNotification()
            }
            mVoiceTime?.let {
                if (mVoiceTime?.visibility == View.VISIBLE) {
                    CallFloatWindowManager.instance.showFloatWindow(mFragmentActivity, it.base, true)
                } else {
                    CallFloatWindowManager.instance.showFloatWindow(mFragmentActivity, -1, true)
                }
            }
        }
    }

    fun onDestroy() {
        RxUtils.disposable(mNotificationDisposable, mDisplayUserDisposable, mWifiDisposable, mCountDownDisposable)
        closeRingtoneVibrator()
        stopTime()
        mWifiOffPublishSubject?.onComplete()
        dismissCallNotification()
        CallFloatWindowManager.instance.hideAndStopFloatWindow(mFragmentActivity)
        CallManager.instance.destroy()
    }

    fun onBackPressed() {
        if (!PermissionUtil.hasPermission(mFragmentActivity)) {
            AlertDialog.Builder(mFragmentActivity)
                    .setTitle(R.string.float_window_permission_dialog_title)
                    .setMessage(R.string.float_window_permission_dialog_message)
                    .setPositiveButton(R.string.float_window_permission_dialog_positive_button) { dialog: DialogInterface?, which: Int -> requestAlertWindowPermission() }
                    .show()
            return
        }
        val topActivity = mMainTaskTopActivity
        val topIntent: Intent? = topActivity?.intent
        if (topActivity == null || topActivity is ChatCallActivity) {
            val intent = Intent(mFragmentActivity, MainActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
            mFragmentActivity.startActivity(intent)
        } else if (topIntent != null) {
            topIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
            mFragmentActivity.startActivity(topIntent)
        }
    }

    private fun requestAlertWindowPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
            intent.data = Uri.parse("package:" + mFragmentActivity.packageName)
            if (CheckUtil.checkAppsIsExist(mFragmentActivity, intent)) {
                mFragmentActivity.startActivityForResult(intent, SETTINGS_OVERLAY_PERMISSION)
            } else {
                GlobalUI.getInstance().showToast(R.string.float_window_permission_mission_toast)
            }
        }
    }

    fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == SETTINGS_OVERLAY_PERMISSION) {
            if (PermissionUtil.hasPermissionOnActivityResult(mFragmentActivity)) {
                CallFloatWindowManager.instance.destroyFloatWindow(mFragmentActivity)
            } else {
                SimpleTask.postDelay({ GlobalUI.getInstance().showToast(R.string.float_window_permission_mission_toast) }, 250)
            }
        }
    }

    private fun initView() {
        mUserAvatar = mFragmentActivity.findViewById(R.id.user_avatar)
        mUserNickname = mFragmentActivity.findViewById(R.id.user_nickname)
        mVoiceStatus = mFragmentActivity.findViewById(R.id.voice_status)
        mVoiceTime = mFragmentActivity.findViewById(R.id.voice_time)
        mVoiceNetworkStatus = mFragmentActivity.findViewById(R.id.voice_network_status)
        mCallLayout = mFragmentActivity.findViewById(R.id.voice_call_layout)
        mVoiceMute = mFragmentActivity.findViewById(R.id.voice_mute)
        mVoiceCancel = mFragmentActivity.findViewById(R.id.voice_cancel)
        mVoiceHandsFree = mFragmentActivity.findViewById(R.id.voice_hands_free)
        mVoiceHandsFreeTitle = mFragmentActivity.findViewById(R.id.voice_hands_free_title)
        mVoiceReceiveLayout = mFragmentActivity.findViewById(R.id.voice_receive_layout)
        mVoiceReject = mFragmentActivity.findViewById(R.id.voice_reject)
        mVoiceAnswer = mFragmentActivity.findViewById(R.id.voice_answer)
        mVoiceFullScreenExit = mFragmentActivity.findViewById(R.id.voice_fullscreen_exit)

        mFragmentActivity.background.layoutParams.width = LocalDisplay.SCREEN_WIDTH_PIXELS
        mFragmentActivity.background.layoutParams.height = LocalDisplay.SCREEN_HEIGHT_PIXELS
    }

    private fun initBind() {
        mVoiceMute?.setOnClickDebounceListener { mVoiceMute?.let { CallManager.instance.setMute(it.isChecked) } }
        mVoiceHandsFree?.setOnClickDebounceListener { CallManager.instance.isEnableSpeaker = mVoiceHandsFree?.isChecked }
        mVoiceCancel?.setOnClickDebounceListener {
            if (TextUtils.isEmpty(mFuid)) {
                return@setOnClickDebounceListener
            }
            sendCallMessage()
            hangup(HangupReason.HANGUP)
        }
        mVoiceReject?.setOnClickDebounceListener {
            sendCallMessage()
            rejectAndFinish()
        }
        mVoiceAnswer?.setOnClickDebounceListener {
            receive()
            logEvent(ACCEPT, 0)
        }
        mVoiceFullScreenExit?.setOnClickDebounceListener {
            UTUtil.getInstance().logEvent("voice_chat_shrink")
            onBackPressed()
        }
        mFragmentActivity.charge_button.setOnClickDebounceListener {
            Router.instance.gotoCoinProductListAndBalanceActivity(mFragmentActivity)
            mFragmentActivity.charge_layout.visibility = View.GONE
            mCountDownDisposable?.dispose()
        }
    }

    @SuppressLint("CheckResult")
    private fun initBaseSupport() {
        mWifiOffPublishSubject = PublishSubject.create()
        mWifiOffPublishSubject?.let {
            mWifiDisposable = it
                    .throttleFirst(2000, TimeUnit.MILLISECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe({ GlobalUI.getInstance().showToast("当前为非 wifi 网络, 不影响通话功能使用") }) { initBaseSupport() }
        }
        if (!NetworkStatusManager.getInstance().isWifi) {
            mWifiOffPublishSubject?.onNext(true)
        }
    }

    @SuppressLint("CheckResult")
    private fun initPermissions() {
        if (mFragmentActivity.isFinishing || mFragmentActivity.isDestroyed) {
            return
        }
        RxPermissions(mFragmentActivity)
                .request(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .subscribe({ granted: Boolean ->
                    if (granted) {
                        checkNotificationPermission()
                        processData()
                    } else {
                        GlobalUI.getInstance().showToast("请检查权限是否开启")
                        finish()
                    }
                }) { obj: Throwable -> obj.printStackTrace() }
    }

    private fun initHeadset() {
        val audioManager = AppContext.getContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
                ?: return
        audioManager.requestAudioFocus(sOnAudioFocusChangeListener, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
        if (audioManager.isWiredHeadsetOn || audioManager.isBluetoothA2dpOn) {
            headsetOn()
        } else {
            headsetOff()
        }
    }

    private fun processData() {
        if (!NetUtils.isConnected(AppContext.getContext(), true)) {
            finish()
            return
        }
        if (TextUtils.isEmpty(mFuid)) {
            finish()
            return
        }
        showUserData(mFuid)
        processStatus()
    }

    @SuppressLint("CheckResult")
    private fun showUserData(uid: String?) {
        mDisplayUserDisposable = Completable.fromAction { UserInfoDataProvider.getInstance().ensureUser(uid) }
                .compose(RxUtils.ioToMainCompletableScheduler<Any>())
                .subscribe {
                    val user: User = UserInfoDataProvider.getInstance().fetchFromMemory(uid)
                    ImageViewUtil.loadAvatarRoundWithBoard(mUserAvatar, user, 96, 2, R.color.user_info_avatar_border, true)
                    loadBackground(mFragmentActivity.background, user)
                    mUserNickname?.setUser(user)
                }
    }

    private val isCalling: Boolean
        get() = CallManager.instance.isCalling

    private fun processStatus() {
        mVoiceStatus?.visibility = View.VISIBLE
        if (mIsCaller) {
            mVoiceStatus?.text = "正在等待对方接受"
            call()
            showCallStatus()
        } else {
            mVoiceStatus?.text = "邀请你语音通话"
            playRingtoneVibrator()
            showReceiveStatus()
        }
    }

    private fun showCallStatus() {
        mCallLayout?.visibility = View.VISIBLE
        mVoiceReceiveLayout?.visibility = View.GONE
    }

    private fun showReceiveStatus() {
        mCallLayout?.visibility = View.GONE
        mVoiceReceiveLayout?.visibility = View.VISIBLE
    }

    private fun startTime() {
        mVoiceStatus?.visibility = View.GONE
        mVoiceTime?.visibility = View.VISIBLE
        mVoiceTime?.let {
            it.base = SystemClock.elapsedRealtime()
            it.start()
            CallFloatWindowManager.instance.showFloatWindow(mFragmentActivity, it.base, false)
        }
    }

    private fun stopTime() {
        mVoiceTime?.stop()
    }

    private fun finish() {
        stopTime()
        mFragmentActivity.finishAndRemoveTask()
    }

    private fun sendCallMessage() {
        val hasConnect = mCallDurationInS > 0
        mFuid?.let {
            if (hasConnect) {
                val duration = mCallDurationInS.toInt()
                CallData.sendVoiceStatusMessageForCall(it, duration.toLong(), mFromType ?: "")
                logEvent(HANGUP, duration)
            } else {
                if (mIsCaller) {
                    CallData.sendVoiceStatusMessageForCancel(it)
                    logEvent(CANCEL, 0)
                } else {
                    CallData.sendVoiceStatusMessageForReject(it)
                    logEvent(REJECT, 0)
                }
            }
        }
    }

    private fun rejectAndFinish() {
        reject()
        finish()
    }

    private fun call() {
        CallData.getCallParams(mFuid, AppConsumer { jsonData ->
            val params = fromJson(jsonData)
            if (params.isInvalid) {
                finish()
                return@AppConsumer
            }
            CallManager.instance.call(params, object : AppCallback<Boolean> {
                override fun onSuccess(t: Boolean) {
                }

                override fun onError(e: Throwable) {
                    finish()
                }
            })
            playRingtone()
        })
    }

    private fun reject() {
        CallManager.instance.response(mFuid, REFUSE)
    }

    private fun hangup(typeForLog: String) {
        if (CallManager.instance.isCalling && !CallManager.instance.isLocalCalling) {
            CallData.hangup(mFuid, typeForLog)
        }

        CallManager.instance.hangUp(mFuid, CallHangUpType.POSITIVE)
    }

    private fun receive() {
        CallManager.instance.response(mFuid, ACCEPT)
    }

    private fun playRingtone() {
        if (mRingtoneMediaPlayer != null && mRingtoneMediaPlayer?.isPlaying == true) {
            return
        }
        try {
            mRingtoneMediaPlayer = MediaPlayer.create(AppContext.getContext(), R.raw.raw_chat_voice_ringtone)
            mRingtoneMediaPlayer?.isLooping = true
            mRingtoneMediaPlayer?.start()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun closeRingtone() {
        mRingtoneMediaPlayer?.pause()
        mRingtoneMediaPlayer?.stop()
        mRingtoneMediaPlayer?.reset()
        mRingtoneMediaPlayer?.release()
        mRingtoneMediaPlayer?.setOnPreparedListener(null)
        mRingtoneMediaPlayer = null
    }

    private fun playVibratorLooping() {
        mVibratorDisposable = Flowable.interval(0, 6, TimeUnit.SECONDS)
                .onBackpressureDrop()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ aLong: Long? -> playVibrator() }) { obj: Throwable -> obj.printStackTrace() }
    }

    private fun playVibrator() {
        if (mVibrator == null) {
            mVibrator = AppContext.getContext().getSystemService(Service.VIBRATOR_SERVICE) as? Vibrator
        }
        mVibrator?.vibrate(2000)
    }

    private fun closeVibrator() {
        RxUtils.disposable(mVibratorDisposable)
        mVibrator?.cancel()
        mVibrator = null
    }

    private fun playRingtoneVibrator() {
        playRingtone()
        playVibratorLooping()
    }

    private fun closeRingtoneVibrator() {
        closeRingtone()
        closeVibrator()
    }

    private fun headsetOn() {
        if (mIsHeadset) {
            return
        }
        mIsHeadset = true
        mVoiceHandsFree?.isEnabled = false
        mVoiceHandsFree?.alpha = 0.5f
        mVoiceHandsFree?.isChecked = false
        mVoiceHandsFreeTitle?.alpha = 0.5f
        CallManager.instance.isEnableSpeaker = false
    }

    private fun headsetOff() {
        if (!mIsHeadset) {
            return
        }
        mIsHeadset = false
        mVoiceHandsFree?.isEnabled = true
        mVoiceHandsFree?.alpha = 1f
        mVoiceHandsFreeTitle?.alpha = 1f
    }

    private fun showPoorNetworkStatus() {
        mVoiceNetworkStatus?.visibility = View.VISIBLE
    }

    private fun dismissPoorNetworkStatus() {
        mVoiceNetworkStatus?.visibility = View.GONE
    }

    private fun logEvent(event: String, duration: Int) {
        val params = Bundle()
        params.putString("target_uid", mFuid)
        if (TextUtils.equals(CallData.ActionType.CANCEL, event)) {
            UTUtil.getInstance().logEvent("voice_chat_cancel", params)
        } else if (TextUtils.equals(CallData.ActionType.REJECT, event)) {
            UTUtil.getInstance().logEvent("voice_chat_refuse", params)
        } else if (TextUtils.equals(CallData.ActionType.ACCEPT, event)) {
            UTUtil.getInstance().logEvent("voice_chat_accept", params)
        } else if (TextUtils.equals(CallData.ActionType.HANGUP, event)) {
            params.putInt("call_duration", duration)
            UTUtil.getInstance().logEvent("voice_chat_hangup", params)
        }
    }

    private fun showCallNotification() {
        mFuid?.let {
            VoiceCallNotificationUtils.instance.showCallNotification(it, mIsCaller, false)
        }
    }

    private fun dismissCallNotification() {
        VoiceCallNotificationUtils.instance.dismissCallNotification()
    }

    override fun onCallFailed(fuid: String, errorType: String) {
        when (errorType) {
            CallFailType.NO_RESPONSE -> GlobalUI.getInstance().showToast("对方暂不方便接听")
            CallFailType.ILLEGAL_ARGUMENT -> GlobalUI.getInstance().showToast("参数错误")
            CallFailType.NOT_LOGIN -> GlobalUI.getInstance().showToast("暂未连接上服务器，请稍后再试")
            CallFailType.UNKNOWN -> GlobalUI.getInstance().showToast("未知错误")
        }
        logEventForCallFailed("unknown")
        hangup(HangupReason.UNKNOWN)
        finish()
    }

    override fun onRespondCall(fuid: String, responseType: String) {}
    override fun onCallResponded(fuid: String, responseType: String) {
        when (responseType) {
            CallResponseType.BUSY_LINE, CallResponseType.REFUSE -> {
                GlobalUI.getInstance().showToast("对方暂不方便接听")
                logEventForCallFailed(responseType)
                hangup(HangupReason.UNKNOWN)
                finish()
            }
            CallResponseType.ACCEPT -> {
            }
        }
    }

    override fun onCancelCall(fuid: String) {
        logEventForCallFailed("cancel")
        finish()
    }

    override fun onCallCanceled(callParams: CallParams) {
        finish()
    }

    override fun onCallConnecting(fuid: String) {}
    override fun onCallConnected(fuid: String) {
        startTime()
        showCallStatus()
        closeRingtoneVibrator()
        connectedWithServer(fuid)
    }

    private fun connectedWithServer(fuid: String) {
        if (mIsCaller) {
            return
        }
        CallData.establishConnection(fuid)
    }

    override fun onCallDisconnected(fuid: String, @HangUpTypeDef hangUpType: String) {
        if (hangUpType == CallHangUpType.NEGATIVE) {
            CallData.hangup(mFuid, HangupReason.UNKNOWN)
        }
        finish()
    }

    override fun onNetStatusReported(good: Boolean, uid: String) {
        if (good) {
            dismissPoorNetworkStatus()
        } else {
            showPoorNetworkStatus()
        }
    }

    override fun onAudioDeviceChanged(headset: Boolean) {
        if (headset) {
            headsetOn()
        } else {
            headsetOff()
        }
    }

    override fun onStatus(totalDurationInS: Long) {
        mCallDurationInS = totalDurationInS
    }

    override fun onMessageSend(message: CallMessage) {}
    override fun onMessageReceive(message: CallMessage) {
        when (message.getType()) {
            ACTION -> onActionMessageReceive(message)
            SYSTEM -> onSystemMessageReceive(message)
        }
    }

    private fun onActionMessageReceive(message: CallMessage) {
        when (message.attrs?.optString("actionType")) {
            ActionMessageType.HANGUP -> {
                if (mIsCaller) {
                    sendCallMessage()
                }
                hangup(HangupReason.COIN_NOT_ENOUGH)
            }
        }
    }

    private fun onSystemMessageReceive(message: CallMessage) {
        when (message.attrs?.optString("subtype")) {
            SystemMessageType.EARNING_TIP -> {
                TextViewUtil.displayOrGone(mFragmentActivity.earning_tip, message.attrs?.optString("earningDesc"))
            }
            SystemMessageType.COIN_NOT_ENOUGH -> {
                val countDown = CountDown.createFromJson(message.attrs?.optJson("countDown"))
                mFragmentActivity.charge_layout.visibility = if (countDown.shouldDoUpdateByServers()) View.VISIBLE else View.GONE
                mCountDownDisposable?.dispose()
                mCountDownDisposable = Observable.interval(0, 1, TimeUnit.SECONDS)
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            if (!countDown.shouldDoUpdateByServers()) {
                                mCountDownDisposable?.dispose()
                                return@subscribe
                            }
                            mFragmentActivity.count_down_desc.text = mFragmentActivity.getString(R.string.call_coin_not_enough_count_down_desc, countDown.digitalCountDownTextByServers)
                        }
            }
        }
    }

    private fun checkNotificationPermission() {
        val notificationEnable: Boolean = CheckUtil.isNotificationChannelEnabled(mFragmentActivity, NotificationData.GroupId.CALL, NotificationData.ChannelId.CALL_CHAT)
        if (!notificationEnable) {
            showNotificationPermissionDialog()
        }
    }

    private fun showNotificationPermissionDialog() {
        AlertDialog.Builder(mFragmentActivity)
                .setMessage("请给予「电话」相关的通知权限，以保证 App 能够正常工作")
                .setPositiveButton("确定") { _, _ -> Router.instance.gotoNotificationSettings() }
                .show()
    }

    private fun loadBackground(avatar: SimpleDraweeView?, user: User) {
        avatar?.setViewTag(Constant.GlobalViewTagDefine.VIEW_TAG_FOR_USER, user)
        val thumbnailParam = UserImageLoadParam.newBuilder()
                .setUser(user, 56, 56) // same size with the avatar in R.layout.item_main_conversation
                .setPostProcessor(IterativeBoxBlurPostProcessor(2, 4))
                ?.setOverlayResId(R.drawable.chat_call_background_overlay_shape)
                ?.build()
        val param = UserImageLoadParam.newBuilder()
                .setUser(user, LocalDisplay.SCREEN_WIDTH_DP, LocalDisplay.SCREEN_HEIGHT_DP)
                .setPostProcessor(IterativeBoxBlurPostProcessor(2, 4))
                ?.setOverlayResId(R.drawable.chat_call_background_overlay_shape)
                ?.setLowResImageLoadParam(thumbnailParam)
                ?.build()
        ImageViewUtil.loadImage(avatar, param)
    }

    private fun logEventForCallFailed(responseType: String) {
        val param = Bundle()
        param.putString("disconnect_type", responseType)
        UTUtil.getInstance().logEvent("call_failed", param)
    }

    override fun onLocalAudioMuteStatusChanged(mute: Boolean) {
        super.onLocalAudioMuteStatusChanged(mute)
        logEventForAudioDisable(mute)
    }

    private fun logEventForAudioDisable(disable: Boolean) {
        if (disable) {
            mDisableAudioStartTime = System.currentTimeMillis()
            VoiceCallLogger.disableAudio()
        } else {
            val duration = (System.currentTimeMillis() - mDisableAudioStartTime) / 1000
            VoiceCallLogger.enableAudio(duration)
            mDisableAudioStartTime = 0
        }
    }

    companion object {
        private val sOnAudioFocusChangeListener = OnAudioFocusChangeListener { }
    }

    init {
        mIsCaller = mFragmentActivity.intent.getBooleanExtra(Constant.IntentKey.KEY_CHAT_CALL_IS_CALLER, false)
        mFuid = mFragmentActivity.intent.getStringExtra(Constant.PARAM_UID)
        mFromType = mFragmentActivity.intent.getStringExtra(Constant.PARAM_FROM)
        if (mFuid == null || mFromType == null) {
            mFragmentActivity.finishAndRemoveTask()
        } else {
            CallManager.instance.create(this)
            initView()
            initBind()
            initBaseSupport()
            initPermissions()
            initHeadset()
        }
    }
}